var gamejs = require("gamejs");
var Sprite = require("gamejs/sprite").Sprite;
var radarModule = require("js/radar");
var obstacleModule = require("js/obstacle");

var loadingNightSceneModule = require("js/scenes/loadingNightScene");
var storeSceneModule = require("js/scenes/storeScene");
var pauseSceneModule = require("js/scenes/pauseScene");
var LaserTurret = require("js/turrets/laserTurret").LaserTurret;
var SlowingTurret = require("js/turrets/slowingTurret").SlowingTurret;
var RocketTurret = require("js/turrets/rocketTurret").RocketTurret;
var GunTurret = require("js/turrets/gunTurret").GunTurret;
/**
 * DayScene, the scene where player can build radars, turrets and obstacles.
 */

/**
 * Creates a DayScene object, here the player can modify the map.
 *
 * @param {ScenesDirector} director The ScenesDirector object that directs the game.
 * @param {Match} match The Match object representing the game.
 *
 * @constructor
 */
var DayScene = exports.DayScene = function(director, match) {
	this.director = director;
	this.match = match;
	this.selectedItem = null;
	this.toPlaceItem = null;
	this.timer = DAY_TIME;
	this.font = new gamejs.font.Font("15px Verdana");

	// HUD background image
	this.hudBackground = gamejs.image.load(IMAGE_ROOT + "hudBackground.png");
	this.hudBackground.setAlpha(0.5);
	// image
	this.pause = new Sprite();
	this.pause.image = gamejs.image.load(IMAGE_ROOT + "pause.png");
	this.pause.rect = new gamejs.Rect([5, 5], this.pause.image.getSize());

	// to night image
	this.disabledToNight = gamejs.image.load(IMAGE_ROOT + "disabledToNight.png");
	this.enabledToNight = gamejs.image.load(IMAGE_ROOT + "toNight.png");
	this.canToNight = false;
	this.toNight = new Sprite();
	this.toNight.image = this.disabledToNight;
	this.toNight.rect = new gamejs.Rect([10, 90], this.toNight.image.getSize());

	// build image
	this.build = new Sprite();
	this.build.image = gamejs.image.load(IMAGE_ROOT + "build.png");
	this.build.rect = new gamejs.Rect([10, 160], this.build.image.getSize());

	// sell image
	this.disabledSell = gamejs.image.load(IMAGE_ROOT + "disabledSell.png");
	this.enabledSell = gamejs.image.load(IMAGE_ROOT + "sell.png");
	this.canSell = false;
	this.sell = new Sprite();
	this.sell.image = this.disabledSell;
	this.sell.rect = new gamejs.Rect([10, 240], this.sell.image.getSize());

	// upgrade image
	this.disabledUpgrade = gamejs.image.load(IMAGE_ROOT + "disabledUpgrade.png");
	this.enabledUpgrade = gamejs.image.load(IMAGE_ROOT + "upgrade.png");
	this.canUpgrade = false;
	this.upgrade = new Sprite();
	this.upgrade.image = this.disabledUpgrade;
	this.upgrade.rect = new gamejs.Rect([10, 320], this.upgrade.image.getSize());

	// info image
	this.disabledShowInfo = gamejs.image.load(IMAGE_ROOT + "disabledShowInfo.png");
	this.enabledShowInfo = gamejs.image.load(IMAGE_ROOT + "showInfo.png");
	this.canInfo = false;
	this.showInfo = new Sprite();
	this.showInfo.image = this.disabledShowInfo;
	this.showInfo.rect = new gamejs.Rect([10, 400], this.showInfo.image.getSize());

	// play day theme via director
	this.director.getSoundManager().stop();
	this.director.getSoundManager().playDay();
};

/**
 * Takes an item so the player can place it in the map.
 *
 * @param {Object} item The item that the player have to place.
 *      The given item MUST have this properties:
 *      - image: the image to draw before it is placed;
 *      - name: the item name;
 *      - constructor: the function that create the item.
 *      The given item can also have this properties:
 *      - level: the level of the item to place,
 *          for example this is used by obstacle.
 */
DayScene.prototype.setToPlaceItem = function(item) {
	this.toPlaceItem = item;
	// place the item at the map center
	var centerX = Math.round(WIDTH_OFFSET + MAP_WIDTH / 2);
	var centerY = Math.round(HEIGHT_OFFSET + MAP_HEIGHT / 2);
	this.toPlaceItem.topLeft = [centerX, centerY];
};

/**
 * Updates the scene and its contents, managing the various events.
 *
 * @param {number} msDuration The time past from the last call, in ms.
 */
DayScene.prototype.update = function(msDuration) {
	// updates the match and everything else in cascade
	this.match.update(msDuration);

	this.timer -= msDuration;

	if(this.timer <= 0) {
		// if time is over go to night
		this.director.pushScene(new loadingNightSceneModule.LoadingNightScene(this.director, this.match));

		return;
	}

	var events = gamejs.event.get();

	for (i = 0; i < events.length; i++) {
		var currentEvent = events[i];
		if(this.toPlaceItem) {
			// there's an object to place in the map
			var dim = this.toPlaceItem.image.getSize();
			if(currentEvent.type == gamejs.event.MOUSE_MOTION) {
				// move the pictures
				var newPos = currentEvent.pos;
				var topleft = [newPos[X] - dim[WIDTH] / 2, newPos[Y] - dim[HEIGHT] / 2];

				// avoid invalid positions
				if(topleft[X] < WIDTH_OFFSET) {
					topleft[X] = WIDTH_OFFSET;
				}
				if(topleft[X] >= (WIDTH_OFFSET + MAP_WIDTH - dim[WIDTH])) {
					topleft[X] = (WIDTH_OFFSET + MAP_WIDTH - dim[WIDTH]) - 1;
				}
				if(topleft[Y] < HEIGHT_OFFSET) {
					topleft[Y] = HEIGHT_OFFSET;
				}
				if(topleft[Y] >= (HEIGHT_OFFSET + MAP_HEIGHT - dim[HEIGHT])) {
					topleft[Y] = (HEIGHT_OFFSET + MAP_HEIGHT - dim[HEIGHT]) - 1;
				}

				this.toPlaceItem.topLeft = topleft;

				// go to the next event
				continue;
			}

			if(currentEvent.type == gamejs.event.MOUSE_UP) {
				// add the item to the map
				var point = currentEvent.pos;

				// manage boundary click
				if(point[X] < (WIDTH_OFFSET + dim[WIDTH] / 2)) {
					point[X] = (WIDTH_OFFSET + dim[WIDTH] / 2);
				}
				if(point[X] >= (WIDTH_OFFSET + MAP_WIDTH - dim[WIDTH] / 2)) {
					point[X] = (WIDTH_OFFSET + MAP_WIDTH - dim[WIDTH] / 2) - 1;
				}
				if(point[Y] < (HEIGHT_OFFSET + dim[HEIGHT] / 2)) {
					point[Y] = (HEIGHT_OFFSET + dim[HEIGHT] / 2);
				}
				if(point[Y] >= (HEIGHT_OFFSET + MAP_HEIGHT - dim[HEIGHT] / 2)) {
					point[Y] = (HEIGHT_OFFSET + MAP_HEIGHT - dim[HEIGHT] / 2) - 1;
				}
				
				// point where to place the item
				var actualPoint = [point[X] - WIDTH_OFFSET, point[Y] - HEIGHT_OFFSET];
				// function that create the item
				var constructor = this.toPlaceItem.constructor;
				// level at which create the item, if any
				var level = this.toPlaceItem.level;
				
				// don't care about what type of item is to place, we just need
				// that it is a GameEntity
				if(level === undefined) {
					this.match.getMap().addGameEntity(
						new constructor(this.match, actualPoint)
					);
				}
				else {
					this.match.getMap().addGameEntity(
						new constructor(this.match, actualPoint, level)
					);
				}
				
				this.toPlaceItem = null;
				
				// the item is placed, don't process other events
				break;
			}
		}

		// process only one valid mouse click(this is the cause of the break statements)
		if (currentEvent.type == gamejs.event.MOUSE_UP) {
			var point = currentEvent.pos;
			if (this.pause.rect.collidePoint(point)) {
				// click on pause
				this.selectedItem = null;
				this.director.pushScene(new pauseSceneModule.PauseScene(this.director, this.match));
				// no break statement because selectedItem is changed,
				// need to update
			}

			if (this.canToNight && this.toNight.rect.collidePoint(point)) {
				// click on to night
				this.director.pushScene(new loadingNightSceneModule.LoadingNightScene(this.director, this.match));
				break;
			}

			if (this.build.rect.collidePoint(point)) {
				// click on build
				this.selectedItem = null;
				this.director.pushScene(new storeSceneModule.StoreScene(this.director, this.match));
				// no break statement because selectedItem is changed,
				// need to update
			}

			// there's an object selected
			if(this.selectedItem) {
				if (this.canSell && this.sell.rect.collidePoint(point)) {
					// click on sell
					this.selectedItem.sell();
					//item sold
					this.selectedItem = null;
					// no break statement because selectedItem is changed,
					// need to update
				}

				if (this.canUpgrade && this.upgrade.rect.collidePoint(point)) {
					// click on upgrade
					this.selectedItem.upgrade();
					// no break statement because selectedItem is changed,
					// need to update
				}

				if (this.canShowInfo && this.showInfo.rect.collidePoint(point)) {
					// click on show info
					this.director.pushScene(new InfoScene(this.director, this.selectedItem));
					break;
				}
			}

			// checks if the click is on an item of the map
			var mapPoint = [point[X] - WIDTH_OFFSET, point[Y] - HEIGHT_OFFSET];
			var selRadars = this.match.getMap().getRadars().collidePoint(mapPoint);
			var selTurrets = this.match.getMap().getTurrets().collidePoint(mapPoint);
			var selObstacles = this.match.getMap().getObstacles().collidePoint(mapPoint);
			var numSelected = selRadars.length + selTurrets.length + selObstacles.length;
			if(numSelected == 1) {
				// there is just one item selected
				if(selRadars[0]) {
					this.selectedItem = selRadars[0];
				}

				if(selTurrets[0]) {
					this.selectedItem = selTurrets[0];
				}

				if(selObstacles[0]) {
					this.selectedItem = selObstacles[0];
				}
			}
			else {
				// there are zero or more than one items selected: selection not valid
				this.selectedItem = null;
			}

			// if an item is selected, checks if it can be upgraded, sold or has some info to show
			if(this.selectedItem) {
				if(this.selectedItem.upgrade && this.selectedItem.canUpgrade()) {
					this.canUpgrade = true;
				}
				else {
					this.canUpgrade = false;
				}

				if(this.selectedItem.sell && this.selectedItem.isSaleable()) {
					this.canSell = true;
				}
				else {
					this.canSell = false;
				}

				if(this.selectedItem.getInfo) {
					this.canShowInfo = true;
				}
				else {
					this.canShowInfo = false;
				}
			}
			else {
				//nothing selected
				this.canUpgrade = false;
				this.canSell = false;
				this.canShowInfo = false;
			}
		}
		else if (currentEvent.type == gamejs.event.MOUSE_MOTION) {
			var point = currentEvent.pos;
			if (this.pause.rect.collidePoint(point))
				document.getElementsByTagName("body")[0].style.cursor ='pointer';
			else if (this.canToNight && this.toNight.rect.collidePoint(point))
				document.getElementsByTagName("body")[0].style.cursor ='pointer';
			else if (this.build.rect.collidePoint(point))
				document.getElementsByTagName("body")[0].style.cursor ='pointer';
			else
				document.getElementsByTagName("body")[0].style.cursor ='default';
		}
		
	}

	// checks if can go to night(need a radar and a turret)
	var radarPlaced = this.match.getMap().hasRadars();
	var turretPlaced = this.match.getMap().hasTurrets();
	this.canToNight = (radarPlaced && turretPlaced);

	// sets the correct image(enabled/disabled)
	this.toNight.image = this.canToNight ? this.enabledToNight : this.disabledToNight;
	this.sell.image = this.canSell ? this.enabledSell : this.disabledSell;
	this.upgrade.image = this.canUpgrade ? this.enabledUpgrade : this.disabledUpgrade;
	this.showInfo.image = this.canShowInfo ? this.enabledShowInfo : this.disabledShowInfo;
};

/**
 * Changes to night the map background
 */
DayScene.prototype.setActive = function() {
	this.match.getMap().setDay();
};

/**
 * Draws the scene and its contents in the director Surface.
 */
DayScene.prototype.draw = function() {
	var surface = this.director.getSurface();
	surface.blit(this.hudBackground);
	this.pause.draw(surface);
	this.toNight.draw(surface);
	this.build.draw(surface);
	this.sell.draw(surface);
	this.upgrade.draw(surface);
	this.showInfo.draw(surface);
	// draws the match(health, credits and score) and everything else (the map) in cascade
	this.match.draw(surface);

	// draws the item to place, if any
	if(this.toPlaceItem) {
		surface.blit(this.toPlaceItem.image, this.toPlaceItem.topLeft);
	}

	// writes the remaining time
	gamejs.draw.arc(
			surface,
			"rgb(220,220,220)",
			 new gamejs.Rect([5, 85],[ 60, 60]),
			0,
			Math.round(360 * this.timer / DAY_TIME),
			4
		);
	//surface.blit(this.font.render((this.timer / 1000).toFixed(1), "#FF0000"), [20, 70]);


	if (this.selectedItem) {
		if (this.canSell) {
			// writes the credits received if the selected item will sold
			surface.blit(this.font.render(this.selectedItem.getResaleValue(), "#82E0FF"), [35, 290]);
		}

		if ( ! this.selectedItem.isAtMaximumLevel()) {
			// writes the credits needed to upgrade the selected item
			surface.blit(this.font.render(this.selectedItem.getUpgradePrice(), "#82E0FF"), [35, 370]);
		}
	}
};